home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fscache / fscacheOps.c < prev    next >
C/C++ Source or Header  |  1991-07-10  |  41KB  |  1,363 lines

  1. /* 
  2.  * fsCacheOps.c --
  3.  *
  4.  *    Cache routines that are monitored with the lock in the per-file
  5.  *    cacheInfo structure.  This includes high level read and write
  6.  *    routines, and routines that fiddle with the attributes that
  7.  *    are cached.
  8.  *    
  9.  *
  10.  * Copyright 1987 Regents of the University of California
  11.  * All rights reserved.
  12.  * Permission to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose and without
  14.  * fee is hereby granted, provided that the above copyright
  15.  * notice appear in all copies.  The University of California
  16.  * makes no representations about the suitability of this
  17.  * software for any purpose.  It is provided "as is" without
  18.  * express or implied warranty.
  19.  */
  20.  
  21. #ifndef lint
  22. static char rcsid[] = "$Header: /sprite/src/kernel/fscache/RCS/fscacheOps.c,v 9.15 91/03/30 17:07:57 mgbaker Exp Locker: mendel $ SPRITE (Berkeley)";
  23. #endif not lint
  24.  
  25.  
  26. #include <sprite.h>
  27. #include <fs.h>
  28. #include <fsutil.h>
  29. #include <fscache.h>
  30. #include <fsconsist.h>
  31. #include <fsNameOps.h>
  32. #include <fsdm.h>
  33. #include <fsStat.h>
  34. #include <fsutilTrace.h>
  35. #include <fslcl.h>
  36. #include <fscacheBlocks.h>
  37. #include <vm.h>
  38. #include <spriteTime.h>
  39. #include <timer.h>
  40. #include <sys.h>
  41. #include <rpc.h>
  42.  
  43. #define    BLOCK_ALIGNED(offset) (((offset) & ~FS_BLOCK_OFFSET_MASK) == (offset))
  44.  
  45. #ifdef SOSP91
  46. Fs_SospMigStats    fs_SospMigStats;
  47. #endif SOSP91
  48.  
  49. /*
  50.  * Cache I/O is serialized using a monitor lock on the cache state for
  51.  * each file.
  52.  */
  53. #define LOCKPTR (&cacheInfoPtr->lock)
  54.  
  55.  
  56. /*
  57.  * ----------------------------------------------------------------------------
  58.  *
  59.  * Fscache_UpdateFile --
  60.  *
  61.  *     This routine updates the cacheInfo for a file based on info returned
  62.  *    from the server at open time.  It checks version numbers and the
  63.  *    cachability of the file, and will do any required invalidations.
  64.  *
  65.  * Results:
  66.  *    True if the file in the cache is different than before.  This is
  67.  *    used to tell VM that the cached segment representing the file
  68.  *    is no longer valid.
  69.  *
  70.  * Side effects:
  71.  *    Updates the version number.  May invalidate old blocks.
  72.  *
  73.  * ----------------------------------------------------------------------------
  74.  *
  75.  */
  76. ENTRY Boolean
  77. Fscache_UpdateFile(cacheInfoPtr, openForWriting, version, cacheable, attrPtr)
  78.     Fscache_FileInfo *cacheInfoPtr;    /* Cache state of file to update. */
  79.     Boolean        openForWriting;    /* TRUE if opening for writing */
  80.     int            version;    /* Version number used to verify
  81.                      * our cached data blocks. */
  82.     Boolean        cacheable;    /* TRUE if server says we can cache. */
  83.     Fscache_Attributes    *attrPtr;    /* Attributes from server */
  84. {
  85.     register Boolean outOfDate;
  86.     Boolean changed = FALSE;
  87. #ifdef CONSIST_DEBUG
  88.     extern int fsTraceConsistMinor;
  89. #endif
  90.     LOCK_MONITOR;
  91.  
  92.     /* 
  93.      * See if we have a good cached copy.  Note: if we open for writing
  94.      * the returned version number will be one greater than ours
  95.      * if no-one else has modified the file since we cached it.
  96.      */
  97.  
  98.     if (openForWriting) {
  99.     outOfDate = (cacheInfoPtr->version < version - 1);
  100.     } else {
  101.     outOfDate = (cacheInfoPtr->version < version);
  102.     }
  103. #ifdef CONSIST_DEBUG
  104.     if (fsTraceConsistMinor == cacheInfoPtr->hdrPtr->fileID.minor) {
  105.     printf("Fscache_UpdateFile: <%d,%d> version %d->%d, %s, %s\n",
  106.             cacheInfoPtr->hdrPtr->fileID.major,
  107.             cacheInfoPtr->hdrPtr->fileID.minor,
  108.             cacheInfoPtr->version, version,
  109.             (cacheable ? "cacheable" : "not-cacheable"),
  110.             (outOfDate ? "out of date" : "not out of date"));
  111.     }
  112. #endif /* CONSIST_DEBUG */
  113.     if (version > cacheInfoPtr->version) {
  114.     /*
  115.      * Update the version of the handle, ie. we just opened for writing
  116.      * or had an outOfDate version.
  117.      */
  118.     cacheInfoPtr->version = version;
  119.     changed = TRUE;
  120.     }
  121.     if (cacheInfoPtr->flags & FSCACHE_FILE_GONE) {
  122.     /*
  123.      * Reset the deleted bit.  By this time any deletion
  124.      * actions will have completed.
  125.      */
  126.     cacheInfoPtr->flags &= ~FSCACHE_FILE_GONE;
  127.     }
  128.  
  129.     /*
  130.      * If we were caching and the file is no longer cacheable, or our copy
  131.      * is outOfDate, we need to invalidate our cache.  Note that we do
  132.      * the cache invalidate with our previous notion of the size.
  133.      */
  134.     if (!cacheable || outOfDate) {
  135.     fs_Stats.handle.cacheFlushes++;
  136.     Fscache_FileInvalidate(cacheInfoPtr, 0, FSCACHE_LAST_BLOCK);
  137.     }
  138.     if (outOfDate) {
  139.     fs_Stats.handle.versionMismatch++;
  140.     cacheInfoPtr->attr = *attrPtr;
  141.     }
  142.  
  143.     /*
  144.      * Propogate the cachability of the handle.
  145.      */
  146.     if (cacheable) {
  147.     if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  148.         /*
  149.          * The handle wasn't client cacheable before.  In this
  150.          * case mark the handle as cacheable and update the cached
  151.          * attributes since they could have changed 
  152.          * while we didn't have the file cached.
  153.          */
  154.         cacheInfoPtr->attr = *attrPtr;
  155.         cacheInfoPtr->flags &= ~FSCACHE_FILE_NOT_CACHEABLE;
  156.     }
  157.     } else {
  158.     cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  159.     }
  160.  
  161.     /* 
  162.      * Update the handle's access time.  The access time doesn't get
  163.      * pushed out to all clients concurrently read-sharing a file,
  164.      * so we grab it here if we are out-of-date.
  165.      */
  166.     if (attrPtr->accessTime > cacheInfoPtr->attr.accessTime) {
  167.     cacheInfoPtr->attr.accessTime = attrPtr->accessTime;
  168.     }
  169.     UNLOCK_MONITOR;
  170.     return (changed);
  171. }
  172.  
  173. /*
  174.  * ----------------------------------------------------------------------------
  175.  *
  176.  * Fscache_UpdateAttrFromClient --
  177.  *
  178.  *     This is used on the server to update the attributes of a handle
  179.  *    that has been cached on a client.  Called at close time with
  180.  *    the attributes the client sends over with the close RPC.
  181.  *    The client's times are checked against the servers to ensure
  182.  *    that they only increase and never move backwards.
  183.  *
  184.  * Results:
  185.  *    None.
  186.  *
  187.  * Side effects:
  188.  *    Updates the access and modify time if they are greater than
  189.  *    the local attribute.  Updates the first and last byte indexes.
  190.  *
  191.  * ----------------------------------------------------------------------------
  192.  *
  193.  */
  194. ENTRY void
  195. Fscache_UpdateAttrFromClient(clientID, cacheInfoPtr, attrPtr)
  196.     int clientID;                /* Client, for warning msg */
  197.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to update. */
  198.     register Fscache_Attributes    *attrPtr;    /* Attributes from client */
  199. {
  200.     LOCK_MONITOR;
  201.  
  202.     if (attrPtr->modifyTime > cacheInfoPtr->attr.modifyTime) {
  203.     cacheInfoPtr->attr.modifyTime = attrPtr->modifyTime;
  204.     }
  205.     if (attrPtr->accessTime > cacheInfoPtr->attr.accessTime) {
  206.     cacheInfoPtr->attr.accessTime = attrPtr->accessTime;
  207.     }
  208.     if (cacheInfoPtr->attr.lastByte > attrPtr->lastByte) {
  209.     printf(
  210.     "Fscache_UpdateAttrFromClient %d: \"%s\" <%d,%d> short size %d not %d\n",
  211.         clientID,
  212.         Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  213.         cacheInfoPtr->hdrPtr->fileID.major,
  214.         cacheInfoPtr->hdrPtr->fileID.minor,
  215.         attrPtr->lastByte, cacheInfoPtr->attr.lastByte);
  216.     } else {
  217.     cacheInfoPtr->attr.lastByte = attrPtr->lastByte;
  218.     }
  219.     cacheInfoPtr->attr.firstByte = attrPtr->firstByte;
  220.  
  221.     (void)Fsdm_UpdateDescAttr((Fsio_FileIOHandle *)cacheInfoPtr->hdrPtr, 
  222.         &cacheInfoPtr->attr, -1);
  223.     UNLOCK_MONITOR;
  224. }
  225.  
  226. /*
  227.  * ----------------------------------------------------------------------------
  228.  *
  229.  * Fscache_UpdateDirSize --
  230.  *
  231.  *     This is used on the server to update the size of a directory
  232.  *    when it grows due to additions.  Note that directories don't
  233.  *    get smaller.
  234.  *
  235.  * Results:
  236.  *    None.
  237.  *
  238.  * Side effects:
  239.  *    Updates the last byte index.
  240.  *
  241.  * ----------------------------------------------------------------------------
  242.  *
  243.  */
  244. ENTRY void
  245. Fscache_UpdateDirSize(cacheInfoPtr, newLastByte)
  246.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to update. */
  247.     register int newLastByte;            /* New last byte index */
  248. {
  249.     LOCK_MONITOR;
  250.     if (newLastByte > cacheInfoPtr->attr.lastByte) {
  251.     cacheInfoPtr->attr.lastByte = newLastByte;
  252.     }
  253.     UNLOCK_MONITOR;
  254. }
  255.  
  256. /*
  257.  * ----------------------------------------------------------------------------
  258.  *
  259.  * Fscache_UpdateAttrFromCache --
  260.  *
  261.  *     This is used on a client to update the given attributes from
  262.  *    information it has cached.  A client caches the access time,
  263.  *    modify time, and size of a file.  When the server returns attributes,
  264.  *    this routine is called to complete them from info cached here
  265.  *    on the client.
  266.  *
  267.  * Results:
  268.  *    None.
  269.  *
  270.  * Side effects:
  271.  *    Updates the access and modify time of *attrPtr if they are less than
  272.  *    the cached value.  Always updates the first and last byte indexes
  273.  *    with the cached value.
  274.  *
  275.  * ----------------------------------------------------------------------------
  276.  *
  277.  */
  278. ENTRY void
  279. Fscache_UpdateAttrFromCache(cacheInfoPtr, attrPtr)
  280.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to check. */
  281.     register Fs_Attributes    *attrPtr;    /* Attributes from server */
  282. {
  283.     LOCK_MONITOR;
  284.     if ((cacheInfoPtr->version == attrPtr->version) &&
  285.     (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) == 0) {
  286.     if (cacheInfoPtr->attr.accessTime > attrPtr->accessTime.seconds) {
  287.         attrPtr->accessTime.seconds = cacheInfoPtr->attr.accessTime;
  288.     }
  289.     if (cacheInfoPtr->attr.modifyTime > attrPtr->dataModifyTime.seconds) {
  290.         attrPtr->dataModifyTime.seconds = cacheInfoPtr->attr.modifyTime;
  291.     }
  292.     attrPtr->size = cacheInfoPtr->attr.lastByte + 1;
  293.     if (cacheInfoPtr->attr.firstByte > 0) {
  294.         attrPtr->size -= cacheInfoPtr->attr.firstByte;
  295.     }
  296.     }
  297.     UNLOCK_MONITOR;
  298. }
  299.  
  300. /*
  301.  * ----------------------------------------------------------------------------
  302.  *
  303.  * Fscache_GetCachedAttr --
  304.  *
  305.  *     This is used on a server to fill out the attributes returned to
  306.  *    a client for caching there.
  307.  *
  308.  * Results:
  309.  *    None.
  310.  *
  311.  * Side effects:
  312.  *    None.
  313.  *
  314.  * ----------------------------------------------------------------------------
  315.  *
  316.  */
  317. ENTRY void
  318. Fscache_GetCachedAttr(cacheInfoPtr, versionPtr, attrPtr)
  319.     register Fscache_FileInfo    *cacheInfoPtr;    /* Cache state to update. */
  320.     register int        *versionPtr;    /* Version number of file */
  321.     register Fscache_Attributes    *attrPtr;    /* New attributes from server */
  322. {
  323.     LOCK_MONITOR;
  324.     *versionPtr = cacheInfoPtr->version;
  325.     *attrPtr = cacheInfoPtr->attr;
  326.     UNLOCK_MONITOR;
  327. }
  328.  
  329. /*
  330.  * ----------------------------------------------------------------------------
  331.  *
  332.  * Fscache_UpdateCachedAttr --
  333.  *
  334.  *     This is called during an Fs_SetAttributes call to update attributes
  335.  *    that are cached in a handle.
  336.  *
  337.  * Results:
  338.  *    None.
  339.  *
  340.  * Side effects:
  341.  *    Updates the times, permissions, file type, and ownership info,
  342.  *    depending on the flags argument.
  343.  *
  344.  * ----------------------------------------------------------------------------
  345.  *
  346.  */
  347. ENTRY void
  348. Fscache_UpdateCachedAttr(cacheInfoPtr, attrPtr, flags)
  349.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state to update. */
  350.     register Fs_Attributes   *attrPtr;        /* New attributes */
  351.     register int         flags;        /* What attrs to update */
  352. {
  353.     LOCK_MONITOR;
  354.     if (flags & FS_SET_TIMES) {
  355.     cacheInfoPtr->attr.accessTime = attrPtr->accessTime.seconds;
  356.     cacheInfoPtr->attr.modifyTime = attrPtr->dataModifyTime.seconds;
  357.     cacheInfoPtr->attr.createTime = attrPtr->createTime.seconds;
  358.     }
  359.     if (flags & FS_SET_MODE) {
  360.     cacheInfoPtr->attr.permissions = attrPtr->permissions;
  361.     }
  362.     if (flags & FS_SET_OWNER) {
  363.     if (attrPtr->uid >= 0) {
  364.         cacheInfoPtr->attr.uid = attrPtr->uid;
  365.     }
  366.     if (attrPtr->gid >= 0) {
  367.         cacheInfoPtr->attr.gid = attrPtr->gid;
  368.     }
  369.     }
  370.     if ((flags & FS_SET_FILE_TYPE) &&
  371.     attrPtr->userType != FS_USER_TYPE_UNDEFINED) {
  372.     cacheInfoPtr->attr.userType = attrPtr->userType;
  373.     }
  374.     UNLOCK_MONITOR;
  375. }
  376.  
  377. /*
  378.  * ----------------------------------------------------------------------------
  379.  *
  380.  * Fscache_CheckVersion --
  381.  *
  382.  *     This is used during recovery on a server to see if the client
  383.  *    has an ok version of the file.
  384.  *
  385.  * Results:
  386.  *    FS_VERSION_MISMATCH if the client's version number is out-of-date.
  387.  *
  388.  * Side effects:
  389.  *    None, except for a print statement.
  390.  *
  391.  * ----------------------------------------------------------------------------
  392.  *
  393.  */
  394. ENTRY ReturnStatus
  395. Fscache_CheckVersion(cacheInfoPtr, version, clientID)
  396.     register Fscache_FileInfo    *cacheInfoPtr;    /* Cache state to check. */
  397.     int                version;
  398.     int                clientID;
  399. {
  400.     ReturnStatus status = SUCCESS;
  401.     LOCK_MONITOR;
  402.     if (version != cacheInfoPtr->version) {
  403.     printf(
  404.     "Version mismatch: clt %d, srv %d, file \"%s\" <%d,%d>, from client %d\n",
  405.         version, cacheInfoPtr->version, Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  406.         cacheInfoPtr->hdrPtr->fileID.major,
  407.         cacheInfoPtr->hdrPtr->fileID.minor, clientID);
  408.     status = FS_VERSION_MISMATCH;
  409.     }
  410.     UNLOCK_MONITOR;
  411.     return(status);
  412. }
  413.  
  414. /*
  415.  * ----------------------------------------------------------------------------
  416.  *
  417.  * Fscache_OkToScavenge --
  418.  *
  419.  *     This is called at handle scavenge time to see if it is ok to
  420.  *    scavenge the handle.  This calls a routine in fsBlockCache.c
  421.  *    which gets the global cache monitor lock because the blocksInCache
  422.  *    attribute and FS_FILE_ON_DIRTY list flags is modified under that lock.
  423.  *
  424.  * Results:
  425.  *    TRUE if there is no information in the cache for the file.
  426.  *
  427.  * Side effects:
  428.  *    None.
  429.  *
  430.  * ----------------------------------------------------------------------------
  431.  *
  432.  */
  433. ENTRY Boolean
  434. Fscache_OkToScavenge(cacheInfoPtr)
  435.     register Fscache_FileInfo    *cacheInfoPtr;    /* Cache state to check. */
  436. {
  437.     register Boolean ok;
  438.     LOCK_MONITOR;
  439.     ok = FscacheBlockOkToScavenge(cacheInfoPtr);
  440.     UNLOCK_MONITOR;
  441.     return(ok);
  442. }
  443.  
  444. /*
  445.  * ----------------------------------------------------------------------------
  446.  *
  447.  * Fscache_Consist --
  448.  *
  449.  *     This is called from ProcessConsist to take a cache consistency
  450.  *    action in response to a callback from the file server.
  451.  *
  452.  * Results:
  453.  *    The return status from the block cache operations, plus the
  454.  *    values of the attributes we have cached here on the client.
  455.  *
  456.  * Side effects:
  457.  *    Will writeback and/or invalidate the cache according to the
  458.  *    request by the server.
  459.  *
  460.  * ----------------------------------------------------------------------------
  461.  *
  462.  */
  463. ENTRY ReturnStatus
  464. Fscache_Consist(cacheInfoPtr, flags, cachedAttrPtr)
  465.     register Fscache_FileInfo    *cacheInfoPtr;
  466.     int                flags;
  467.     Fscache_Attributes        *cachedAttrPtr;
  468. {
  469.     ReturnStatus status;
  470.     int firstBlock;
  471.     int numSkipped;
  472.     int mig;
  473.  
  474.     LOCK_MONITOR;
  475.  
  476.     if (cacheInfoPtr->attr.firstByte == -1) {
  477.     firstBlock = 0;
  478.     } else {
  479.     firstBlock = cacheInfoPtr->attr.firstByte / FS_BLOCK_SIZE;
  480.     }
  481.     status = SUCCESS;
  482.     mig = (flags & FSCONSIST_MIGRATION) ? FSCACHE_WB_MIGRATION : 0;
  483.     switch (flags & ~(FSCONSIST_DEBUG|FSCONSIST_MIGRATION)) {
  484.     case FSCONSIST_WRITE_BACK_BLOCKS:
  485. #ifdef SOSP91
  486.         cacheInfoPtr->flags |= FSCACHE_CONSIST_WB;
  487. #endif SOSP91
  488.         status = Fscache_FileWriteBack(cacheInfoPtr, firstBlock,
  489.             FSCACHE_LAST_BLOCK, FSCACHE_FILE_WB_WAIT | mig,
  490.                        &numSkipped);
  491.         break;
  492.     case FSCONSIST_CANT_CACHE_NAMED_PIPE:
  493.     case FSCONSIST_INVALIDATE_BLOCKS:
  494.         Fscache_FileInvalidate(cacheInfoPtr, firstBlock, 
  495.                    FSCACHE_LAST_BLOCK);
  496.         cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  497.         break;
  498.     case FSCONSIST_INVALIDATE_BLOCKS | FSCONSIST_WRITE_BACK_BLOCKS:
  499. #ifdef SOSP91
  500.         cacheInfoPtr->flags |= FSCACHE_CONSIST_WBINV;
  501. #endif SOSP91
  502.         status = Fscache_FileWriteBack(cacheInfoPtr, firstBlock,
  503.                        FSCACHE_LAST_BLOCK,
  504.                        FSCACHE_WRITE_BACK_AND_INVALIDATE |
  505.                        FSCACHE_FILE_WB_WAIT | mig,
  506.                        &numSkipped);
  507.         cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  508.         break;
  509.     case FSCONSIST_DELETE_FILE:
  510.         cacheInfoPtr->flags |= FSCACHE_FILE_GONE;
  511.         Fscache_FileInvalidate(cacheInfoPtr, firstBlock, FSCACHE_LAST_BLOCK);
  512.         cacheInfoPtr->flags |= FSCACHE_FILE_NOT_CACHEABLE;
  513.         break;
  514.     case FSCONSIST_WRITE_BACK_ATTRS:
  515.         break;
  516.     default:
  517.         printf("Fscache_Consist: Bad consistency action %x\n", flags);
  518.         status = FS_INVALID_ARG;
  519.         break;
  520.     }
  521.     *cachedAttrPtr = cacheInfoPtr->attr;
  522.  
  523.     UNLOCK_MONITOR;
  524.     return(status);
  525. }
  526.  
  527. /*
  528.  *----------------------------------------------------------------------
  529.  *
  530.  * Fscache_Read --
  531.  *
  532.  *    Read from the block cache.
  533.  *
  534.  * Results:
  535.  *    SUCCESS unless there was an address error or I/O error.
  536.  *
  537.  * Side effects:
  538.  *    Fill in the buffer and the cache with data from the stream.
  539.  *    The cache state for the file is locked to serialize I/O.
  540.  *
  541.  *----------------------------------------------------------------------
  542.  */
  543. ReturnStatus
  544. Fscache_Read(cacheInfoPtr, flags, buffer, offset, lenPtr, remoteWaitPtr)
  545.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state for file. */
  546.     int            flags;        /* FS_USER | etc */
  547.     register Address    buffer;        /* Buffer to fill with file data */
  548.     int         offset;        /* Byte offset */
  549.     int         *lenPtr;    /* In/Out byte count */
  550.     Sync_RemoteWaiter    *remoteWaitPtr;    /* Process info for remote waiting */
  551. {
  552.     register int     size;        /* Amount left to read */
  553.     register int     blockNum;    /* Current block being read */
  554.     register int     toRead;        /* Amount to read each iteration */
  555.     ReturnStatus    status = SUCCESS; /* Return from I/O operations */
  556.     int            firstBlock;    /* First block of the read */
  557.     int            lastBlock;    /* Last block of the read */
  558.     Boolean        found;        /* For fetching blocks from cache */
  559.     Fscache_Block    *blockPtr;    /* For fetching blocks from cache */
  560.     int            dontBlock;    /* FSCACHE_DONT_BLOCK */
  561. #ifdef SOSP91
  562.     Boolean        isForeign = FALSE;    /* Due to migration? */
  563. #endif SOSP91
  564.  
  565.     /*
  566.      * Serialiaze access to the cache for this file.
  567.      */
  568.     LOCK_MONITOR;
  569.  
  570.     if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  571.     status = FS_NOT_CACHEABLE;
  572.     goto exit;
  573.     }
  574. #ifdef SOSP91
  575.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  576.     if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  577.         (proc_RunningProcesses[0]->genFlags &
  578.         (PROC_FOREIGN | PROC_MIGRATING))) {
  579.         isForeign = TRUE;
  580.     }
  581.     }
  582. #endif SOSP91
  583.     /*
  584.      * Determine the offset at which to read.
  585.      */
  586.     if (offset > cacheInfoPtr->attr.lastByte) {
  587.     *lenPtr = 0;
  588.     status = SUCCESS;
  589.     goto exit;
  590.     }
  591.  
  592.     if ((remoteWaitPtr != (Sync_RemoteWaiter *)NIL) &&
  593.     (remoteWaitPtr->pid != (Proc_PID)NIL)) {
  594.     dontBlock = FSCACHE_DONT_BLOCK;
  595.     } else {
  596.     dontBlock = 0;
  597.     }
  598.     /*
  599.      * Fetch blocks one at a time.
  600.      */
  601.     size = *lenPtr;
  602.     firstBlock = (unsigned int) offset / FS_BLOCK_SIZE; 
  603.     lastBlock = (unsigned int) (offset + size - 1) / FS_BLOCK_SIZE;
  604.  
  605.     for (blockNum = firstBlock; 
  606.      blockNum <= lastBlock && offset <= cacheInfoPtr->attr.lastByte; 
  607.      blockNum++, size -= toRead, buffer += toRead, offset += toRead) {
  608.  
  609.     /*
  610.      * Initiate read ahead on the next block.
  611.      */
  612.     FscacheReadAhead(cacheInfoPtr, blockNum + 1);
  613.  
  614.     /*
  615.      * Determine the number of bytes to transfer out of the cache block
  616.      * in this go around.
  617.      */
  618.     toRead = size;
  619.     if ((unsigned int) (offset + size - 1) / FS_BLOCK_SIZE > blockNum) {
  620.         toRead = (blockNum + 1) * FS_BLOCK_SIZE - offset;
  621.     }
  622.     if (toRead > cacheInfoPtr->attr.lastByte - offset + 1) {
  623.         toRead = cacheInfoPtr->attr.lastByte - offset + 1;
  624.     }
  625.  
  626.     /* 
  627.      * Get the block from the cache.  If the block isn't in the cache
  628.      * then read data into it.
  629.      */
  630.     Fscache_FetchBlock(cacheInfoPtr, blockNum,
  631.         FSCACHE_DATA_BLOCK|dontBlock, &blockPtr, &found);
  632.     if (blockPtr == (Fscache_Block *)NIL) {
  633.         /*
  634.          * Cache is full.
  635.          */
  636.         status = FS_WOULD_BLOCK;
  637.         Fsutil_WaitListInsert(fscacheFullWaitList, remoteWaitPtr);
  638.         break;
  639.     }
  640.     fs_Stats.blockCache.readAccesses++;
  641. #ifdef SOSP91
  642.     if (isForeign) {
  643.         fs_SospMigStats.blockCache.readAccesses++;
  644.     }
  645. #endif SOSP91
  646.         
  647.     if (found) {
  648.         if (blockPtr->timeDirtied != 0) {
  649.         fs_Stats.blockCache.readHitsOnDirtyBlock++;
  650. #ifdef SOSP91
  651.         if (isForeign) {
  652.             fs_SospMigStats.blockCache.readHitsOnDirtyBlock++;
  653.         }
  654. #endif SOSP91
  655.         } else {
  656.         fs_Stats.blockCache.readHitsOnCleanBlock++;
  657. #ifdef SOSP91
  658.         if (isForeign) {
  659.             fs_SospMigStats.blockCache.readHitsOnCleanBlock++;
  660.         }
  661. #endif SOSP91
  662.         }
  663.         if (blockPtr->flags & FSCACHE_READ_AHEAD_BLOCK) {
  664.         fs_Stats.blockCache.readAheadHits++;
  665. #ifdef SOSP91
  666.         if (isForeign) {
  667.             fs_SospMigStats.blockCache.readAheadHits++;
  668.         }
  669. #endif SOSP91
  670.         }
  671.     } else {
  672.         /*
  673.          * We didn't find the block in the cache so we have to read it in.
  674.          * Fscache_FetchBlock has set the blockNum and blockAddr (buffer).
  675.          * blockSize gets set as a side-effect of the block read routine.
  676.          */
  677.         status = (cacheInfoPtr->backendPtr->ioProcs.blockRead)
  678.             (cacheInfoPtr->hdrPtr, blockPtr, remoteWaitPtr);
  679. #ifdef lint
  680.         status = Fsio_FileBlockRead(cacheInfoPtr->hdrPtr,
  681.             blockPtr, remoteWaitPtr);
  682.         status = FsrmtFileBlockRead(cacheInfoPtr->hdrPtr,
  683.             blockPtr, remoteWaitPtr);
  684. #endif /* lint */
  685.         if (status != SUCCESS) {
  686.         fs_Stats.blockCache.domainReadFails++;
  687.         Fscache_UnlockBlock(blockPtr, 0, -1, 0, FSCACHE_DELETE_BLOCK);
  688.         break;
  689.         }
  690.         }
  691.  
  692.     /*
  693.      * Copy the bytes out of the cache block.
  694.      */
  695.     if (flags & FS_USER) {
  696.         if (Vm_CopyOut(toRead, 
  697.                   blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK),
  698.               buffer) != SUCCESS) {
  699.         status = SYS_ARG_NOACCESS;
  700.         Fscache_UnlockBlock(blockPtr, 0, -1, 0,
  701.             FSCACHE_CLEAR_READ_AHEAD);
  702.         break;
  703.         }
  704.     } else {
  705.         bcopy(blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK),
  706.               buffer, toRead);
  707.     }
  708.     Fscache_UnlockBlock(blockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  709.     }
  710.     *lenPtr -= size;
  711.     Fs_StatAdd(*lenPtr, fs_Stats.blockCache.bytesRead,
  712.            fs_Stats.blockCache.bytesReadOverflow);
  713. #ifdef SOSP91
  714.     if (isForeign) {
  715.     Fs_StatAdd(*lenPtr, fs_SospMigStats.blockCache.bytesRead,
  716.         fs_SospMigStats.blockCache.bytesReadOverflow);
  717.     }
  718. #endif SOSP91
  719.  
  720. exit:
  721.     if ((status == SUCCESS) ||
  722.     (status == FS_WOULD_BLOCK && (*lenPtr > 0))) {
  723.     cacheInfoPtr->attr.accessTime = Fsutil_TimeInSeconds();
  724.     }
  725.     UNLOCK_MONITOR;
  726.     return(status);
  727. }
  728.  
  729. /*
  730.  *----------------------------------------------------------------------
  731.  *
  732.  * Fscache_Write --
  733.  *
  734.  *    Write to the cache.  Called from the file write and named pipe
  735.  *    write routines.
  736.  * 
  737.  * Results:
  738.  *    A return status, SUCCESS if successful.
  739.  *
  740.  * Side effects:
  741.  *    Data is put into the cache.  Blocks may be read if only partial
  742.  *    blocks are being written.  The cache state is locked during the I/O
  743.  *    to serialize cache access.
  744.  *
  745.  *----------------------------------------------------------------------
  746.  */
  747. ReturnStatus
  748. Fscache_Write(cacheInfoPtr, flags, buffer, offset, lenPtr, remoteWaitPtr)
  749.     register Fscache_FileInfo *cacheInfoPtr;    /* Cache state for the file. */
  750.     int            flags;        /* FS_USER | FS_APPEND | 
  751.                      * FS_SERVER_WRITE_THRU */
  752.     register Address     buffer;        /* Buffer to write from */
  753.     int         offset;        /* Byte offset */
  754.     int         *lenPtr;    /* In/Out byte count */
  755.     Sync_RemoteWaiter     *remoteWaitPtr;    /* Process info for remote waiting */
  756. {
  757.     register int     size;        /* The current size left to write */
  758.     register int     toWrite;    /* Amount to write each iteration */
  759.     int            toAlloc;    /* Amount of disk space to allocate.*/
  760.     register int     blockNum;    /* The current block being written */
  761.     Fscache_Block     *blockPtr;    /* From fetching cached blocks */
  762.     int            blockSize;    /* The number of bytes in the current
  763.                      * block. */
  764.     ReturnStatus     status = SUCCESS; /* Return from I/O operations */
  765.     int            firstBlock;    /* The first block of the write */
  766.     int            lastBlock;    /* The last block to write */
  767.     Boolean        found;        /* From fetching cached blocks */
  768.     int            oldOffset;    /* Initial value of the offset */
  769.     int            lastFileBlock;    /* Last block in the file */
  770.     int            blockAddr;    /* For allocating blocks */
  771.     Boolean        newBlock;    /* A brand new block was allocated. */
  772.     int            modTime;    /* File modify time. */
  773.     Boolean        dontBlock;    /* TRUE if lower levels shouldn't block
  774.                      * because we can block up higher */
  775. #ifdef SOSP91
  776.     Boolean        isForeign = FALSE;    /* Due to migration? */
  777. #endif SOSP91
  778.  
  779.     /*
  780.      * Serialize access to the cache for this file.
  781.      */
  782.     LOCK_MONITOR;
  783.  
  784.     if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  785.     /*
  786.      * Not cached.  The flag is checked here under monitor lock.
  787.      */
  788.     status = FS_NOT_CACHEABLE;
  789.     goto exit;
  790.     }
  791.     if (cacheInfoPtr->flags & FSCACHE_FILE_GONE) {
  792.     /*
  793.      * A delayed write is arriving as the file is being deleted.
  794.      */
  795.     printf( "Write to deleted file #%d\n",
  796.             cacheInfoPtr->hdrPtr->fileID.minor);
  797.     status = FS_FILE_REMOVED;
  798.     *lenPtr = 0;
  799.     goto exit;
  800.     }
  801. #ifdef SOSP91
  802.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  803.     if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  804.         (proc_RunningProcesses[0]->genFlags &
  805.         (PROC_FOREIGN | PROC_MIGRATING))) {
  806.         isForeign = TRUE;
  807.     }
  808.     }
  809. #endif SOSP91
  810.     /*
  811.      * Determine where to start writing.
  812.      */
  813.     if (flags & FS_APPEND) {
  814.     offset = cacheInfoPtr->attr.lastByte + 1;
  815.     }
  816.     oldOffset = offset;
  817.     size = *lenPtr;
  818.     *lenPtr = 0;
  819.  
  820.     /*
  821.      * Determine the range of blocks to write and where the current last block
  822.      * in the file is.
  823.      */
  824.     firstBlock = (unsigned int) offset / FS_BLOCK_SIZE; 
  825.     lastBlock = (unsigned int) (offset + size - 1) / FS_BLOCK_SIZE;
  826.     if (cacheInfoPtr->attr.lastByte == -1) {
  827.     lastFileBlock = -1;
  828.     } else {
  829.     lastFileBlock = ((unsigned int) cacheInfoPtr->attr.lastByte) /
  830.                 FS_BLOCK_SIZE;
  831.     }
  832.     /*
  833.      * If we have a handle on a process then our caller can block it.
  834.      * Otherwise we have to block at a low level in FetchBlock.
  835.      */
  836.     if ((remoteWaitPtr != (Sync_RemoteWaiter *)NIL) &&
  837.     (remoteWaitPtr->pid != (Proc_PID)NIL)) {
  838.     dontBlock = FSCACHE_DONT_BLOCK;
  839.     } else {
  840.     dontBlock = 0;
  841.     }
  842.  
  843.     /*
  844.      * Put the data into the cache a block at a time.
  845.      */
  846.     for (blockNum = firstBlock; 
  847.      blockNum <= lastBlock; 
  848.      blockNum++, size -= toWrite, buffer += toWrite, offset += toWrite) {
  849.  
  850.     /*
  851.      * Determine the number of bytes to write into the cache block
  852.      * this go around and the number of bytes to allocate on disk.
  853.      */
  854.     if ((unsigned int) (offset + size - 1) / FS_BLOCK_SIZE > blockNum) {
  855.         /*
  856.          * Writing will go into the next block.  In this case fill up the 
  857.          * rest of the current block and allocate space for the rest of
  858.          * the current block.
  859.          */
  860.         toWrite = FS_BLOCK_SIZE - (offset & FS_BLOCK_OFFSET_MASK);
  861.         toAlloc = toWrite;
  862.     } else {
  863.         /*
  864.          * The write ends in this block.
  865.          * There are two cases for disk allocation:
  866.          *   1) We are writing before the last byte in the file.  In this
  867.          *      case allocate up to the last byte or the end of the
  868.          *      current block whichever comes first.
  869.          *   2) We are after the last byte in the file.  In this case just
  870.          *        allocate space for the newly written bytes.
  871.          */
  872.         toWrite = size;
  873.         if (offset + toWrite - 1 < cacheInfoPtr->attr.lastByte) {
  874.         if (cacheInfoPtr->attr.lastByte >=
  875.                 (blockNum + 1) * FS_BLOCK_SIZE) {
  876.             toAlloc = FS_BLOCK_SIZE - (offset & FS_BLOCK_OFFSET_MASK);
  877.         } else {
  878.             toAlloc = cacheInfoPtr->attr.lastByte - offset + 1;
  879.         }
  880.         } else {
  881.         toAlloc = toWrite;
  882.         }
  883.     }
  884.  
  885.     /*
  886.      * Allocate space behind the cache block.
  887.      */
  888.     status = (cacheInfoPtr->backendPtr->ioProcs.allocate)(cacheInfoPtr->hdrPtr,
  889.             offset, toAlloc, dontBlock, &blockAddr, &newBlock);
  890. #ifdef lint
  891.     status = Fsdm_BlockAllocate(cacheInfoPtr->hdrPtr,
  892.             offset, toAlloc, dontBlock, &blockAddr, &newBlock);
  893.     status = FsrmtBlockAllocate(cacheInfoPtr->hdrPtr,
  894.             offset, toAlloc, dontBlock, &blockAddr, &newBlock);
  895. #endif /* lint */
  896.  
  897.     if (blockAddr == FSDM_NIL_INDEX) {
  898.         if (status == SUCCESS) {
  899.         status = FS_NO_DISK_SPACE;
  900.         }
  901.         blockPtr = (Fscache_Block *)NIL;
  902.     } else {
  903.         fs_Stats.blockCache.writeAccesses++;
  904. #ifdef SOSP91
  905.         if (isForeign) {
  906.         fs_SospMigStats.blockCache.writeAccesses++;
  907.         }
  908. #endif SOSP91
  909.         
  910.         Fscache_FetchBlock(cacheInfoPtr, blockNum, 
  911.          (int)(FSCACHE_IO_IN_PROGRESS | FSCACHE_DATA_BLOCK | dontBlock),
  912.          &blockPtr, &found);
  913.         if (blockPtr == (Fscache_Block *)NIL) {
  914.         status = FS_WOULD_BLOCK;
  915.         }
  916.     }
  917.     if (blockPtr == (Fscache_Block *)NIL) {
  918.         if (status == FS_NO_DISK_SPACE) {
  919.         /*
  920.          * Limit the number of "Alloc failed" messages to 1 per file.
  921.          * Servers with hard-copy consoles like this feature.
  922.          */
  923.         if ((cacheInfoPtr->flags & FSCACHE_ALLOC_FAILED) == 0) {
  924.             cacheInfoPtr->flags |= FSCACHE_ALLOC_FAILED;
  925.             printf("Fscache_Write: Alloc failed <%d,%d> \"%s\" %s\n",
  926.             cacheInfoPtr->hdrPtr->fileID.major,
  927.             cacheInfoPtr->hdrPtr->fileID.major,
  928.             Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  929.             "DISK FULL");
  930.         }
  931.         }
  932.         break;
  933.     } else {
  934.         cacheInfoPtr->flags &= ~FSCACHE_ALLOC_FAILED;
  935.     }
  936.  
  937.  
  938.     if (toWrite == FS_BLOCK_SIZE) {
  939.         if (found) {
  940.         fs_Stats.blockCache.overWrites++;
  941. #ifdef SOSP91
  942.         if (isForeign) {
  943.             fs_SospMigStats.blockCache.overWrites++;
  944.         }
  945. #endif SOSP91
  946.         }
  947.     } else {
  948.         /*
  949.          * Check if are writing into the middle of the file and are not 
  950.          * overwriting the block.  If so have to read the block in if
  951.          * it is not in the cache.
  952.          */
  953.         if (blockNum <= lastFileBlock && !newBlock) {
  954.         if (found) {
  955.             fs_Stats.blockCache.partialWriteHits++;
  956. #ifdef SOSP91
  957.             if (isForeign) {
  958.             fs_SospMigStats.blockCache.partialWriteHits++;
  959.             }
  960. #endif SOSP91
  961.             if (blockPtr->flags & FSCACHE_READ_AHEAD_BLOCK) {
  962.             fs_Stats.blockCache.readAheadHits++;
  963. #ifdef SOSP91
  964.             if (isForeign) {
  965.                 fs_SospMigStats.blockCache.readAheadHits++;
  966.             }
  967. #endif SOSP91
  968.             }
  969.         } else {
  970.             fs_Stats.blockCache.partialWriteMisses++;
  971. #ifdef SOSP91
  972.             if (isForeign) {
  973.             fs_SospMigStats.blockCache.partialWriteMisses++;
  974.             }
  975. #endif SOSP91
  976.             status = (cacheInfoPtr->backendPtr->ioProcs.blockRead)
  977.             (cacheInfoPtr->hdrPtr, blockPtr, remoteWaitPtr);
  978. #ifdef lint
  979.             status = Fsio_FileBlockRead(cacheInfoPtr->hdrPtr, 
  980.                 blockPtr, remoteWaitPtr);
  981.             status = FsrmtFileBlockRead(cacheInfoPtr->hdrPtr,
  982.                 blockPtr, remoteWaitPtr);
  983. #endif /* lint */
  984.             if (status != SUCCESS) {
  985.             fs_Stats.blockCache.domainReadFails++;
  986.             Fscache_UnlockBlock(blockPtr, 0, -1, 0,
  987.                 FSCACHE_DELETE_BLOCK);
  988.             break;
  989.             }
  990.         }
  991.         } else {
  992.         /*
  993.          * We are writing to the end of the file or the block
  994.          * that we are writing to is brand new.  In this case zero
  995.          * fill the block if it isn't in the cache yet.
  996.          */
  997.         if (!found) {
  998.             fs_Stats.blockCache.writeZeroFills2++;
  999.             bzero(blockPtr->blockAddr, FS_BLOCK_SIZE);
  1000.         }
  1001.         }
  1002.     }
  1003.  
  1004.     /*
  1005.      * Copy the bytes into the block.
  1006.      */
  1007.     if (flags & FS_USER) {
  1008.         if (Vm_CopyIn(toWrite, buffer, blockPtr->blockAddr + 
  1009.                 (offset & FS_BLOCK_OFFSET_MASK)) != SUCCESS) {
  1010.         status = SYS_ARG_NOACCESS;
  1011.         Fscache_UnlockBlock(blockPtr, 0, -1, 0, FSCACHE_DELETE_BLOCK);
  1012.         break;
  1013.         }
  1014.     } else {
  1015.         bcopy(buffer, blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK), toWrite);
  1016.     }
  1017.  
  1018.     /*
  1019.      * If the block is write-thru then write the data through to the 
  1020.      * server and then check the block back in as clean.
  1021.      * THIS IS A GORY HACK that limits the use of FS_SERVER_WRITE_THRU
  1022.      * to the client.
  1023.      */
  1024.     if (flags & FS_SERVER_WRITE_THRU) {
  1025.         Fs_Stream    dummyStream;
  1026.         Fs_IOParam    io;
  1027.         Fs_IOReply    reply;
  1028.  
  1029.         io.buffer = blockPtr->blockAddr + (offset & FS_BLOCK_OFFSET_MASK);
  1030.         io.length = toWrite;
  1031.         io.offset = offset;
  1032.         io.flags = flags | FS_CLIENT_CACHE_WRITE;
  1033.         io.flags &= ~(FS_USER | FS_SERVER_WRITE_THRU);
  1034.  
  1035.         dummyStream.hdr.fileID.type = -1;
  1036.         dummyStream.ioHandlePtr = cacheInfoPtr->hdrPtr;
  1037.         status = Fsrmt_Write(&dummyStream, &io,
  1038.              (Sync_RemoteWaiter *)NIL, &reply);
  1039.         if (status != SUCCESS) {
  1040.         Fscache_UnlockBlock(blockPtr, 0, -1, 0, FSCACHE_DELETE_BLOCK);
  1041.         break;
  1042.         }
  1043.         modTime = 0;
  1044.     } else {
  1045.         modTime = Fsutil_TimeInSeconds();
  1046.     }
  1047.  
  1048.     /*
  1049.      * Return the block to the cache.  At this time the block
  1050.      * size is changed (by UnlockBlock). 
  1051.      */
  1052.     if (offset + toWrite - 1 > cacheInfoPtr->attr.lastByte) {
  1053.         cacheInfoPtr->attr.lastByte = offset + toWrite - 1;
  1054.     }
  1055.     blockSize = cacheInfoPtr->attr.lastByte + 1 -
  1056.             (blockNum * FS_BLOCK_SIZE);
  1057.     if (blockSize > FS_BLOCK_SIZE) {
  1058.         blockSize = FS_BLOCK_SIZE;
  1059.     }
  1060.     Fscache_UnlockBlock(blockPtr, (unsigned) modTime, blockAddr,
  1061.         blockSize, FSCACHE_CLEAR_READ_AHEAD |
  1062.         ((flags&FS_WRITE_TO_DISK) ?
  1063.             FSCACHE_WRITE_TO_DISK : 0));
  1064.     }
  1065.  
  1066.     *lenPtr = offset - oldOffset;
  1067.     Fs_StatAdd(offset - oldOffset, fs_Stats.blockCache.bytesWritten,
  1068.            fs_Stats.blockCache.bytesWrittenOverflow);
  1069. #ifdef SOSP91
  1070.     if (isForeign) {
  1071.     Fs_StatAdd(offset - oldOffset, fs_SospMigStats.blockCache.bytesWritten,
  1072.            fs_SospMigStats.blockCache.bytesWrittenOverflow);
  1073.     
  1074.     }
  1075. #endif SOSP91
  1076.  
  1077.     /*
  1078.      * Update the firstByte so that Fs_Read knows there is data.
  1079.      * This is support for named pipes, which care about firstByte.
  1080.      */
  1081.     if (cacheInfoPtr->attr.firstByte == -1 && *lenPtr > 0) {
  1082.     cacheInfoPtr->attr.firstByte = 0;
  1083.     }
  1084.     if (!(flags & FS_CLIENT_CACHE_WRITE) && *lenPtr > 0) {
  1085.     /*
  1086.      * Update the modify time unless this write is a flush back from a
  1087.      * user cache in which case we already get the correct mod time
  1088.      * for the file when the client closes.
  1089.      */
  1090.     cacheInfoPtr->attr.modifyTime = Fsutil_TimeInSeconds();
  1091.     }
  1092. exit:
  1093.     if (status == FS_WOULD_BLOCK) {
  1094.     Fsutil_FastWaitListInsert(fscacheFullWaitList, remoteWaitPtr);
  1095.     }
  1096.     UNLOCK_MONITOR;
  1097.     return(status);
  1098. }
  1099.  
  1100. /*
  1101.  *----------------------------------------------------------------------
  1102.  *
  1103.  * Fscache_BlockRead --
  1104.  *
  1105.  *    Return a pointer to the cache block that contains a
  1106.  *    block of a file.  This is used to directly access cache blocks
  1107.  *    and so avoid the cost of a copy.  The number of valid bytes
  1108.  *    in the cache block is returned.
  1109.  *
  1110.  * Results:
  1111.  *    SUCCESS or error when reading file system block.  Upon failure,
  1112.  *    or a zero length read with the allocate flag not set, the cache block 
  1113.  *    is not locked down and the caller doesn't have to worry about it; 
  1114.  *    NIL is returned in *blockPtrPtr.
  1115.  *    This returns FS_WOULD_BLOCK if blockType includes FSCACHE_DONT_BLOCK
  1116.  *    and the cache is full.
  1117.  *
  1118.  * Side effects:
  1119.  *    The cache block is locked down, and its contents are filled in
  1120.  *    from disk if neccessary.  The caller has to unlock the block when done,
  1121.  *    if it is non-NIL.
  1122.  *
  1123.  *----------------------------------------------------------------------
  1124.  */
  1125.  
  1126. ReturnStatus
  1127. Fscache_BlockRead(cacheInfoPtr, blockNum, blockPtrPtr, numBytesPtr, blockType,
  1128.          allocate)
  1129.     register    Fscache_FileInfo *cacheInfoPtr;    /* File to read block from.
  1130.                          * Should be locked on entry */
  1131.     int                blockNum;    /* Block to read. */
  1132.     register    Fscache_Block    **blockPtrPtr;    /* Where to put pointer to 
  1133.                          * block.*/
  1134.     register    int        *numBytesPtr;    /* Return number of bytes 
  1135.                          * read. */
  1136.     int                blockType;    /* One of FSCACHE_DATA_BLOCK
  1137.                          * and FSCACHE_DIR_BLOCK.
  1138.                          * | FSCACHE_DONT_BLOCK */
  1139.     Boolean            allocate;    /* TRUE => return the cache
  1140.                          * block even though there
  1141.                          * is not data in it. */
  1142. {
  1143.     Boolean        found;
  1144.     ReturnStatus    status = SUCCESS;
  1145.     int            offset;
  1146.     Fscache_Block    *blockPtr;
  1147. #ifdef SOSP91
  1148.     Boolean        isForeign = FALSE;    /* Due to migration? */
  1149. #endif SOSP91
  1150.  
  1151.     LOCK_MONITOR;
  1152.  
  1153.     *blockPtrPtr = (Fscache_Block *)NIL;
  1154.     *numBytesPtr = 0;
  1155.  
  1156.    if (cacheInfoPtr->flags & FSCACHE_FILE_NOT_CACHEABLE) {
  1157.     panic( "Fscache_BlockRead, file not cacheable!\n");
  1158.     status = FS_NOT_CACHEABLE;
  1159.     goto exit;
  1160.     }
  1161.     offset = blockNum * FS_BLOCK_SIZE;
  1162.     if (offset > cacheInfoPtr->attr.lastByte) {
  1163.     status = SUCCESS;
  1164.     goto exit;
  1165.     }
  1166. #ifdef SOSP91
  1167.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  1168.     if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  1169.         (proc_RunningProcesses[0]->genFlags &
  1170.         (PROC_FOREIGN | PROC_MIGRATING))) {
  1171.         isForeign = TRUE;
  1172.     }
  1173.     }
  1174. #endif SOSP91
  1175.     fs_Stats.blockCache.readAccesses++;
  1176. #ifdef SOSP91
  1177.     if (isForeign) {
  1178.     fs_SospMigStats.blockCache.readAccesses++;
  1179.     }
  1180. #endif SOSP91
  1181.     if (blockType & FSCACHE_DIR_BLOCK) {
  1182.         fs_Stats.blockCache.dirBlockAccesses++;
  1183. #ifdef SOSP91
  1184.     if (isForeign) {
  1185.         fs_SospMigStats.blockCache.dirBlockAccesses++;
  1186.     }
  1187. #endif SOSP91
  1188.     }
  1189.     Fscache_FetchBlock(cacheInfoPtr, blockNum, blockType,
  1190.             blockPtrPtr, &found);
  1191.     if (*blockPtrPtr == (Fscache_Block *)NIL) {
  1192.     status = FS_WOULD_BLOCK;
  1193.     goto exit;
  1194.     }
  1195.     blockPtr = *blockPtrPtr;
  1196.  
  1197.     if (!found) {
  1198.     /*
  1199.      * Read in the cache block.  If the block isn't full (includes EOF)
  1200.      * then blockSize is set and the rest of the cache block has
  1201.      * been zero filled.
  1202.      */
  1203.     status = (cacheInfoPtr->backendPtr->ioProcs.blockRead)
  1204.             (cacheInfoPtr->hdrPtr, blockPtr, (Sync_RemoteWaiter *) NIL);
  1205. #ifdef lint
  1206.     status = Fsio_FileBlockRead(cacheInfoPtr->hdrPtr,
  1207.         blockPtr, (Sync_RemoteWaiter *) NIL);
  1208.     status = FsrmtFileBlockRead(cacheInfoPtr->hdrPtr,
  1209.         blockPtr, (Sync_RemoteWaiter *) NIL);
  1210. #endif /* lint */
  1211.     if (status == SUCCESS && blockPtr->blockSize == 0 &&
  1212.         offset < cacheInfoPtr->attr.lastByte + 1) {
  1213.         /*
  1214.          * Due to delayed writes the disk descriptor has no space allocated
  1215.          * and the file block read routine thinks we've read past eof.
  1216.          * Actually were in a hole in the file and should return zeros.
  1217.          * The blockRead routine always zero fills for us.
  1218.          */
  1219.         printf("Fscache_BlockRead: Giving zeros to \"%s\" <%d,%d> block %d amount %d\n",
  1220.             Fsutil_HandleName(cacheInfoPtr->hdrPtr),
  1221.             cacheInfoPtr->hdrPtr->fileID.major,
  1222.             cacheInfoPtr->hdrPtr->fileID.minor,
  1223.             blockPtr->blockNum,
  1224.             cacheInfoPtr->attr.lastByte - offset);
  1225.         blockPtr->blockSize = cacheInfoPtr->attr.lastByte - offset;
  1226.     }
  1227.     if ((status != SUCCESS) ||
  1228.         (blockPtr->blockSize == 0 && !allocate)) {
  1229.         /*
  1230.          * We hit a disk error or are really past the end-of-file.
  1231.          */
  1232.         Fscache_UnlockBlock(blockPtr, 0, -1, 0, FSCACHE_DELETE_BLOCK);
  1233.         *blockPtrPtr = (Fscache_Block *)NIL;
  1234.     }
  1235.     } else {
  1236.     if (blockType & FSCACHE_DIR_BLOCK) {
  1237.         fs_Stats.blockCache.dirBlockHits++;
  1238. #ifdef SOSP91
  1239.         if (isForeign) {
  1240.         fs_SospMigStats.blockCache.dirBlockHits++;
  1241.         }
  1242. #endif SOSP91
  1243.     }
  1244.     if (blockPtr->flags & FSCACHE_READ_AHEAD_BLOCK) {
  1245.         fs_Stats.blockCache.readAheadHits++;
  1246. #ifdef SOSP91
  1247.         if (isForeign) {
  1248.         fs_SospMigStats.blockCache.readAheadHits++;
  1249.         }
  1250. #endif SOSP91
  1251.     }
  1252.     if (blockPtr->timeDirtied != 0) {
  1253.         fs_Stats.blockCache.readHitsOnDirtyBlock++;
  1254. #ifdef SOSP91
  1255.         if (isForeign) {
  1256.         fs_SospMigStats.blockCache.readHitsOnDirtyBlock++;
  1257.         }
  1258. #endif SOSP91
  1259.     } else {
  1260.         fs_Stats.blockCache.readHitsOnCleanBlock++;
  1261. #ifdef SOSP91
  1262.         if (isForeign) {
  1263.         fs_SospMigStats.blockCache.readHitsOnCleanBlock++;
  1264.         }
  1265. #endif SOSP91
  1266.     }
  1267.     }
  1268.     if (status == SUCCESS) {
  1269.     *numBytesPtr = blockPtr->blockSize;
  1270.     }
  1271.  
  1272.     if (blockType & FSCACHE_DIR_BLOCK) {
  1273.     fs_Stats.blockCache.dirBytesRead += blockPtr->blockSize;
  1274. #ifdef SOSP91
  1275.     if (isForeign) {
  1276.         fs_SospMigStats.blockCache.dirBytesRead += blockPtr->blockSize;
  1277.     }
  1278. #endif SOSP91
  1279.     } else {
  1280.     Fs_StatAdd(blockPtr->blockSize, fs_Stats.blockCache.bytesRead,
  1281.            fs_Stats.blockCache.bytesReadOverflow);
  1282. #ifdef SOSP91
  1283.     if (isForeign) {
  1284.     Fs_StatAdd(blockPtr->blockSize, fs_SospMigStats.blockCache.bytesRead,
  1285.            fs_SospMigStats.blockCache.bytesReadOverflow);
  1286.         
  1287.     }
  1288. #endif SOSP91
  1289.     }
  1290.     /*
  1291.      * Read ahead the next block.
  1292.      */
  1293.     FscacheReadAhead(cacheInfoPtr, blockNum + 1);
  1294. exit:
  1295.     UNLOCK_MONITOR;
  1296.     return(status);
  1297. }
  1298.  
  1299. /*
  1300.  *----------------------------------------------------------------------
  1301.  *
  1302.  * Fscache_Trunc --
  1303.  *
  1304.  *    Truncate data out of the cache.  This knows how to truncate
  1305.  *    Consuming streams.
  1306.  *
  1307.  * Results:
  1308.  *    The return status of backend truncate.
  1309.  *
  1310.  * Side effects:
  1311.  *    Data blocks are removed from the cache.  The file's first and
  1312.  *    last byte indexes get updated.  The modify time of the file
  1313.  *    gets set.
  1314.  *
  1315.  *----------------------------------------------------------------------
  1316.  */
  1317. ReturnStatus
  1318. Fscache_Trunc(cacheInfoPtr, length, flags)
  1319.     Fscache_FileInfo *cacheInfoPtr;
  1320.     int length;
  1321.     int flags;    /*  FSCACHE_TRUNC_DELETE */
  1322. {
  1323.     int firstBlock;
  1324.     int lastBlock;
  1325.     ReturnStatus status;
  1326.  
  1327.     LOCK_MONITOR;
  1328.  
  1329.     if (flags & FSCACHE_TRUNC_DELETE) {
  1330.     cacheInfoPtr->flags |= FSCACHE_FILE_GONE;
  1331.     }
  1332.     if ((cacheInfoPtr->flags & FS_NOT_CACHEABLE) == 0) {
  1333.     if (length - 1 < cacheInfoPtr->attr.lastByte) {
  1334.         /*
  1335.          * Do file like truncation, leave length bytes at the
  1336.          * beginning of the file.
  1337.          */
  1338.         if (length == 0) {
  1339.         firstBlock = 0;
  1340.         } else {
  1341.         firstBlock = (length - 1) / FS_BLOCK_SIZE + 1;
  1342.         }
  1343.         lastBlock = cacheInfoPtr->attr.lastByte / FS_BLOCK_SIZE;
  1344.             if (length - 1 < cacheInfoPtr->attr.firstByte) {
  1345.                 cacheInfoPtr->attr.lastByte = -1;
  1346.             cacheInfoPtr->attr.firstByte = -1;
  1347.             } else {
  1348.                 cacheInfoPtr->attr.lastByte = length - 1;
  1349.             }
  1350.         Fscache_FileInvalidate(cacheInfoPtr, firstBlock, lastBlock);
  1351.         if (firstBlock > 0) {
  1352.         Fscache_BlockTrunc(cacheInfoPtr, firstBlock - 1,
  1353.                   length - (firstBlock - 1) * FS_BLOCK_SIZE);
  1354.         }
  1355.         }
  1356.     cacheInfoPtr->attr.modifyTime = Fsutil_TimeInSeconds();
  1357.     }
  1358.     status = (cacheInfoPtr->backendPtr->ioProcs.truncate)(cacheInfoPtr->hdrPtr,
  1359.             length, (flags & FSCACHE_TRUNC_DELETE) != 0);
  1360.     UNLOCK_MONITOR;
  1361.     return status;
  1362. }
  1363.